package gc3d.gridspring;

import gc3d.ftp.FTPSettings;
import gc3d.griddata.GridData;

import java.io.File;
import java.io.IOException;

import org.gridgain.grid.Grid;
import org.gridgain.grid.GridConfigurationAdapter;
import org.gridgain.grid.GridException;
import org.gridgain.grid.GridFactory;
import org.gridgain.grid.GridNode;
import org.gridgain.grid.gridify.aop.spring.GridifySpringEnhancer;
import org.gridgain.grid.spi.collision.fifoqueue.GridFifoQueueCollisionSpi;


/**
 * @author Pierrick
 *
 */
public class GridPovRun extends Thread {
	private GridData griddata;
	// encoding data
	private int fps;
	private int x264bitrate; // 800
	private String videoname;

	public GridPovRun(GridData gd, int fps, int x264bitrate) {
		this.griddata = gd;
		this.fps = fps;
		this.x264bitrate = x264bitrate;
		this.videoname = gd.getFileName()+".avi";
	}

	/**
	 * @see java.lang.Thread#run()
	 * @see #render()
	 * @see #encode()
	 */
	public void run() {
		int render = this.render();
		System.out.println(this+".run render = "+render);
		if (render != 0) {
			System.err.println("[ERROR][GridPovRun.run] "+render+" render node(s) failed");
			// TODO reprocess/rerender those files localy ?
			this.griddata.updateTaskStatus("rendering error, "+render+" node(s) failed");
		} else {
			this.griddata.updateTaskStatus("rendering finish, encoding...");
			int encode = this.encode();
			System.out.println(this+".run encode = "+encode);
			if (encode == 0) {
				this.griddata.finishTask(this.videoname);
				System.out.println(this+" succed !");
			} else {
				this.griddata.updateTaskStatus("encoding error ["+encode+" ]");
			}
		}
		System.out.println(this+".run finish");
	}

	/**
	 * Start a local Grid-node, execute our Grid-task (rendering) 
	 * set the ftp-host (default: localhost) to the local-node address
	 * @return rendering result, number of task error, should be 0
	 * @see org.gridgain.grid.GridFactory#start()
	 * @see org.gridgain.grid.gridify.aop.spring.GridifySpringEnhancer#enhance(Object)
	 * @see GridPovRender#render()
	 */
	private int render() {
		int renderreturn = -1;
		try {
			// http://www.gridgainsystems.com/wiki/display/GG15UG/Collision+SPI
			GridConfigurationAdapter cfg = new GridConfigurationAdapter();
			GridFifoQueueCollisionSpi colSpi = new GridFifoQueueCollisionSpi();
			// Limit number of parallel jobs.
			colSpi.setParallelJobsNumber(1);
			// Configure your own collisioin SPI.
			cfg.setCollisionSpi(colSpi);
			// Give a name
			//cfg.setGridName("GC3D");

			Grid gc3d_grid = GridFactory.start(cfg);
			GridNode gn    = gc3d_grid.getLocalNode();

			if (FTPSettings.getFTPhost().equals("localhost")) {
				System.out.println(this+" IP:"+gn.getPhysicalAddress());
				griddata.setHostFTP(gn.getPhysicalAddress());
			}

			GridPov gp = new GridPovRender(griddata);
			gp = GridifySpringEnhancer.enhance(gp);
			renderreturn = gp.render();
		} catch (GridException e) {
			e.printStackTrace();
		} finally {
			GridFactory.stop(true);
		}
		return renderreturn;
	}

	/**
	 * Encode all generated-png in x264 video using MEncoder.
	 * http://www.mplayerhq.hu/DOCS/HTML-single/en/MPlayer.html#mencoder
	 * %MENC_BIN% mf://*.png -mf fps=5:type=png -sws 6 -o gc3d.mp4 -ovc x264 -x264encopts bitrate=800
	 * @return encoding result, should be 0
	 */
	private int encode() {
		int encoderreturn = -1;

		if (System.getenv("FTP_HOME") == null) {
			System.err.println("[ERROR] set/export FTP_HOME=/path/to/folder/ftp/home !");
		} else {
			String mencbin = System.getenv("MENC_BIN");
			if (mencbin == null) {
				System.out.println("[WARN ] You should set/export MENC_BIN=/path/to/file/mencoder/binfile !");
				System.err.println("[INFO ] Using `mencoder` as command, PATH must be up to date");
				mencbin = "mencoder";
			}
			ProcessBuilder pb = new ProcessBuilder(mencbin, 
					"mf://*.png", "-mf", "fps="+fps+":type=png", "-sws", "6", 
					"-o", videoname, "-ovc", "x264", "-x264encopts", "bitrate="+x264bitrate);
			pb.redirectErrorStream(true);
			File workdir = new File(System.getenv("FTP_HOME") 
					+ File.separatorChar + griddata.getRemotePath());
			pb.directory(workdir);
			Process p;
			try {
				System.out.println(this+".run mencoder start");
				p = pb.start();
				// Here: MEncoder is runing
				System.out.println(this+".run mencoder started");
				// we have to read the buffer
				new Thread(new ProcReceiver(p.getInputStream())).start();
				encoderreturn = p.waitFor(); // should be 0
				System.out.println(this+".run mencoder finish");
			} catch (IOException e) {
				e.printStackTrace();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		return encoderreturn;
	}

	/**
	 * @return ftp link to the video
	 */
	public String getVideoLink() {
		return griddata.getLink()+videoname;
	}
}
